package com.dingreading.cloud.mall.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.qyweixin.AccessTokenDto;
import com.dingreading.cloud.common.util.qyweixin.QyWeiXinUtil;
import com.dingreading.cloud.common.util.qyweixin.QyWeixinMsg;
import com.dingreading.cloud.mall.dto.*;
import com.dingreading.cloud.mall.entity.*;
import com.dingreading.cloud.mall.entity.table.ShopCartTableDef;
import com.dingreading.cloud.mall.mapper.ShopCartMapper;
import com.dingreading.cloud.mall.service.*;
import com.dingreading.cloud.mall.util.OrderFormV3Util;
import com.dingreading.cloud.mall.util.ShopCartUtilV2;
import com.dingreading.cloud.mall.util.redis.RedisService;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.BatchArgsSetter;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.update.UpdateChain;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RefreshScope
@Service
public class ShopCartV5ServiceImpl extends BaseServiceImpl<ShopCartMapper, ShopCart, ShopCartTableDef> implements ShopCartV5Service {

    @Override
    protected ShopCartTableDef getTable() {
        return ShopCartTableDef.shopCart;
    }

    @Value("${serverUrl}")
    private String serverUrl;

    @Value("${qyweixin.corpid}")
    private String corpid;
    @Value("${qyweixin.secret}")
    private String secret;
    @Value("${qyweixin.agentid}")
    private String agentid;
    @Value("${qyweixin.mallchatid}")
    private String mallchatid;
    @Value("${qyweixin.managerUserid}")
    private String managerUserid;
    @Value("${qyweixin.thirdUserid}")
    private String thirdUserid;
    @Value("${qyweixin.subManagerUserid}")
    private String subManagerUserid;


    @Resource
    protected OrderFormService orderFormService;
    @Resource
    protected StoresService storesService;
    @Resource
    protected GoodsService goodsService;
    @Resource
    protected GoodsTypeService goodsTypeService;
    @Resource
    protected GoodsTypeComboService goodsTypeComboService;
    @Resource
    protected DeliveryAddressService deliveryAddressService;
    @Resource
    protected CouponStaffService couponStaffService;
    @Resource
    protected CorporationsService corporationsService;
    @Resource
    protected WhStockInService stockInService;
    @Resource
    protected StoreGoodsDiscountService storeGoodsDiscountService;
    @Resource
    protected GoodsCategoryLogService goodsCategoryLogService;
    @Resource
    private ShopCartMapper shopCartMapper;
    @Resource
    private RedisService redisService;

    @Override
    public R<Object> myShopCarts(String storeUid, String staffUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))))
                .and(table.type.eq(1));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());
        List<ShopCart> list = getMapper().selectListByQuery(wrapper);

        double price = 0;
        double originalPrice = 0;
        double discountPrice = 0;
        if (CollectionUtils.isNotEmpty(list)) {
            for (ShopCart cart : list) {
                price = DoubleUtil.sum(price, cart.getPrice());
                originalPrice = DoubleUtil.sum(originalPrice, cart.getOriginalPrice());
                if (cart.getDiscountPrice() != null) {
                    discountPrice = DoubleUtil.sum(discountPrice, cart.getDiscountPrice());
                }
            }
        }

        MyShopCartPriceDto data = new MyShopCartPriceDto();
        data.setPrice(price);
        data.setOriginalPrice(originalPrice);
        data.setDiscountPrice(discountPrice);
        data.setList(list);
        return R.ok(data);
    }

    @Override
    public R<Object> deleteByIdIn(String storeUid, String staffUid, List<Long> ids) {
        QueryCondition queryCondition = table.storeUid.eq(storeUid)
                .and(table.staffUid.eq(staffUid))
                .and(table.id.in(ids));
        List<ShopCart> list = getMapper().selectListByCondition(queryCondition);
        if (CollectionUtils.isEmpty(list))
            return R.fail("未查询到购物车信息");

        // 组合商品的子购物车记录
        List<String> mainShopCartUids = list.stream()
                .filter(shopCart -> shopCart.getMainComboType().equals(1))
                .map(ShopCart::getUid)
                .distinct()
                .collect(Collectors.toList());

        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.status.notIn(EnumType.ShopCart.PAYED.getType(), EnumType.ShopCart.SEND.getType(), EnumType.ShopCart.REFUND.getType()));
        if (CollectionUtils.isNotEmpty(mainShopCartUids))
            condition.and(table.id.in(ids).or(table.mainShopCartUid.in(mainShopCartUids)));
        else
            condition.and(table.id.in(ids));
        int i = getMapper().deleteByCondition(condition);
        if (i <= 0)
            return R.failDel();
        return R.ok();
    }

    @Override
    public R<Object> editNum(String storeUid, String staffUid, String staffName, Long id, Integer num, Integer type) {
        Stores stores = storesService.getByUid(storeUid);
        if (null == stores)
            return R.fail("门店信息获取失败");

        QueryCondition queryCondition = table.storeUid.eq(storeUid)
                .and(table.id.eq(id));
        ShopCart data = getMapper().selectOneByCondition(queryCondition);
        if (data == null)
            return R.fail("购物车记录获取失败");
        if (data.getCode() != null || !data.getStatus().equals(EnumType.ShopCart.WAIT_CONFIRM.getType()))
            return R.fail("修改失败商品状态：" + EnumType.ShopCart.getStatus(data.getStatus()));

        Goods goods = goodsService.getById(data.getGoodsId());
        if (goods == null) return R.fail("未查询到商品");
        if (!goods.getEnabled().equals(1)) return R.fail("商品已下架");
        GoodsType goodsType = goodsTypeService.getByGoodsIdAndGoodsTypeId(data.getGoodsId(), data.getGoodsTypeId());
        if (goodsType == null) return R.fail("未查询到商品规格");
        if (!goodsType.getEnabled().equals(1)) return R.fail("商品规格已下架");

        int buyNum = 0;
        if (num != null) {
            // 修改成填入的数量
            buyNum = num;
        } else if (type != null) {
            // 没有填入数量，自加1或自减1
            if (type.equals(1)) {
                buyNum = data.getBuyNum() + 1;
            } else {
                buyNum = data.getBuyNum() - 1;
            }
        } else {
            return R.fail("修改购买数量错误");
        }
        if (buyNum <= 0)
            return R.fail("购买数量必须大于0");

        if (data.getMainComboType().equals(0)) {
            // 普通商品
            // 获取库存数量
            Map<Long, Integer> stockNumMap = stockInService.getStockNumMap(Collections.singletonList(data.getGoodsTypeId()));
            Integer stockNum = stockNumMap.get(data.getGoodsTypeId());
            // 根据购买记录和出库记录获取商品规格的待出库数量
            int waitSendNum = getWaitSendNum(data.getGoodsTypeId());
            // 判断商品和商品规格状态、最低购买数、库存数量
            String msg = OrderFormV3Util.judgeGoodsAndGoodsType(
                    AccountUtil.isSelfStore(stores.getOperationType()), data.getMainComboType(), goods, goodsType,
                    buyNum, stockNum, waitSendNum
            );
            if (StringUtils.isNotBlank(msg))
                return R.fail(msg);

            // 轻量门店的商品折扣规则
            Double storeGoodsDiscountRate = storeGoodsDiscountService.getDiscountRate(storeUid);

            double weight = NepUtil.nullToZero(goodsType.getWeight());
            double totalWeight = DoubleUtil.mul(weight, buyNum);
            double unitPrice = goodsType.getPrice();
            double price = 0;
            double originalUnitPrice = 0;
            double originalPrice = 0;
            Double discountRate = null;
            double discountPrice = 0;

            // 计算购物车商品的价格（学科折扣）
            ShopCartPriceDto priceDto = ShopCartUtilV2.getDiscountRateUnitPrice(
                    unitPrice, goodsType.getDiscountStatus(), storeGoodsDiscountRate
            );
            originalUnitPrice = priceDto.getOriginalUnitPrice();
            originalPrice = DoubleUtil.mul(buyNum, originalUnitPrice);
            unitPrice = priceDto.getUnitPrice();
            price = DoubleUtil.mul(buyNum, unitPrice);
            discountRate = priceDto.getDiscountRate();
            discountPrice = DoubleUtil.sub(originalPrice, price);

            // 更新购物车的信息
            QueryCondition condition = QueryCondition.createEmpty();
            condition.and(table.id.eq(id))
                    .and(table.staffUid.eq(staffUid))
                    .and(table.status.in(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                    .and(table.code.isNull());
            boolean l = UpdateChain.of(ShopCart.class)
                    .set(table.originalUnitPrice, originalUnitPrice)
                    .set(table.originalPrice, originalPrice)
                    .set(table.unitPrice, unitPrice)
                    .set(table.price, price)
                    .set(table.discountRate, discountRate)
                    .set(table.discountPrice, discountPrice)
                    .set(table.weight, weight)
                    .set(table.totalWeight, totalWeight)
                    .set(table.buyNum, buyNum)
                    .where(condition)
                    .update();
            if (!l)
                return R.fail("修改失败");
        } else {
            // 组合商品
            List<GoodsTypeCombo> goodsTypeComboList = goodsTypeComboService.listByMainGoodsIdAndMainGoodsTypeId(data.getGoodsId(), data.getGoodsTypeId());
            if (CollectionUtils.isEmpty(goodsTypeComboList))
                return R.fail("组合商品信息获取失败");

            HashBasedTable<Long, Long, GoodsTypeCombo> table = HashBasedTable.create();
            for (GoodsTypeCombo typeCombo : goodsTypeComboList) {
                table.put(typeCombo.getGoodsTypeId(), typeCombo.getGoodsId(), typeCombo);
            }

            List<ShopCart> childShopCartList = childListByStoreUidAndStaffUidAndUid(storeUid, staffUid, data.getUid());
            if (CollectionUtils.isEmpty(childShopCartList))
                return R.fail("组合商品内的商品信息获取失败");

            if (table.size() != childShopCartList.size())
                return R.fail("组合商品内的商品数量和购物车记录数量不一致");

            // 获取商品和商品规格信息
            List<Long> childGoodsIds = new ArrayList<>(table.columnKeySet());
            List<Long> childGoodsTypeIds = new ArrayList<>(table.rowKeySet());

            List<Goods> childGoodsList = goodsService.listByIds(childGoodsIds);
            if (CollectionUtils.isEmpty(childGoodsList) || childGoodsIds.size() != childGoodsList.size())
                return R.fail("组合商品内的商品获取失败");
            List<GoodsType> childGoodsTypeList = goodsTypeService.listByIds(childGoodsTypeIds);
            if (CollectionUtils.isEmpty(childGoodsTypeList) || childGoodsTypeIds.size() != childGoodsTypeList.size())
                return R.fail("组合商品内的商品规格获取失败");

            Map<Long, Goods> childGoodsMap = childGoodsList.stream().collect(Collectors.toMap(Goods::getId, Function.identity()));
            Map<Long, GoodsType> childGoodsTypeMap = childGoodsTypeList.stream().collect(Collectors.toMap(GoodsType::getId, Function.identity()));

            for (GoodsType childGoodsType : childGoodsTypeList) {
                if (childGoodsType.getEnabled().equals(0)) {
                    Goods childGoods = childGoodsMap.get(childGoodsType.getGoodsId());
                    return R.fail("组合商品内的商品规格已下架" + childGoods.getName() + "/" + childGoodsType.getName());
                }
            }

            // 轻量门店的商品折扣规则
            Double storeGoodsDiscountRate = storeGoodsDiscountService.getDiscountRate(storeUid);

            // 获取库存数量
            Map<Long, Integer> stockNumMap = stockInService.getStockNumMap(childGoodsTypeIds);
            // 根据购买记录和出库记录获取商品规格的待出库数量
            Map<Long, Integer> waitSendNumMap = getWaitSendNum(childGoodsTypeIds);

            double totalWeight = 0;
            int paymentMethod = 1;

            for (ShopCart childCart : childShopCartList) {
                Long goodsId = childCart.getGoodsId();
                Long goodsTypeId = childCart.getGoodsTypeId();
                Goods childGoods = childGoodsMap.get(goodsId);
                GoodsType childGoodsType = childGoodsTypeMap.get(goodsTypeId);

                GoodsTypeCombo goodsTypeCombo = table.get(goodsTypeId, goodsId);
                if (goodsTypeCombo == null || goodsTypeCombo.getEnabled().equals(0))
                    return R.fail("组合商品内的商品不存在或失效");
                Integer goodsTypeComboNum = goodsTypeCombo.getNum();
                if (goodsTypeComboNum == null || goodsTypeComboNum <= 0)
                    return R.fail("组合商品内的商品可购买数量错误");

                int childBuyNum = buyNum * goodsTypeComboNum;
                // 判断商品和商品规格状态
                String msg = OrderFormV3Util.judgeGoodsAndGoodsType(
                        AccountUtil.isSelfStore(stores.getOperationType()), data.getMainComboType(),
                        childGoods, childGoodsType, childBuyNum, stockNumMap.get(goodsTypeId), waitSendNumMap.get(goodsTypeId)
                );
                if (StringUtils.isNotBlank(msg))
                    return R.fail(msg);

                // 包含有银行转账
                if (paymentMethod == 1 && childGoods.getPaymentMethod().equals(2))
                    paymentMethod = 2;

                // 修改组合商品规格的购物车记录
                ShopCartUtilV2.mdyShopCart(
                        childCart, childGoods, childGoodsType, childBuyNum, staffUid, staffName, null
                );

                totalWeight = DoubleUtil.sum(totalWeight, childCart.getTotalWeight());
            }

            // 修改组合商品规格的购物车记录
            ShopCartUtilV2.mdyMainComboShopCart(
                    data, goods, goodsType, buyNum, paymentMethod, totalWeight, staffUid, staffName, storeGoodsDiscountRate
            );
            // 修改组合商品的购物车购买数量
            saveOrUpdate(data);
            // 修改组合商品的子购物车购买数量
            saveOrUpdateBatch(childShopCartList);
        }
        return R.ok();
    }


    @Override
    public R<Object> addToShopCart(String storeUid, String staffUid, String staffName, Long goodsId, Long goodsTypeId, Integer num) {
        if (num <= 0)
            return R.fail("购买数量必须大于0");

        Stores stores = storesService.getByUid(storeUid);
        if (null == stores)
            return R.fail("门店信息获取失败");
        String storesCorpUid = stores.getCorpUid();

        // 轻量门店的商品折扣规则
        Double storeGoodsDiscountRate = storeGoodsDiscountService.getDiscountRate(storeUid);

        long cartCount = getStaffShopCartCountV3(storeUid, storeUid);
        if (cartCount >= 50) return R.fail("购物车商品已达到50件");

        Goods goods = goodsService.getById(goodsId);
        if (goods == null)
            return R.fail("商品获取失败");
        if (!goods.getEnabled().equals(1))
            return R.fail("商品已下架");
        if (goods.getFreeDeliveryId() == null || goods.getFreeDeliveryId() <= 0)
            return R.fail("商品未设置包邮模板");
        GoodsType goodsType = goodsTypeService.getByGoodsIdAndGoodsTypeId(goodsId, goodsTypeId);
        if (goodsType == null)
            return R.fail("商品规格获取失败");
        if (!goodsType.getEnabled().equals(1))
            return R.fail("商品规格已下架");

        ShopCart data = null;
        if (goodsType.getComboType().equals(0)) {
            // 普通商品
            if (!AccountUtil.isSelfStore(stores.getOperationType()) && num < goods.getMinBuyNum())
                // 非自营门店且非组合商品，判断最低购买数
                return R.fail("购买数量不能低于最少购买数");

            // 获取库存数量
            Map<Long, Integer> stockNumMap = stockInService.getStockNumMap(Collections.singletonList(goodsTypeId));
            int stockNum = stockNumMap.get(goodsTypeId);
            // 根据购买记录和出库记录获取商品规格的待出库数量
            int waitSendNum = getWaitSendNum(goodsTypeId);

            // 获取商品规格的真实可售数，库存数量减去待发货数量
            stockNum = OrderFormV3Util.getGoodsTypeNum(stockNum, waitSendNum);

            data = getByStaffIdAndGoodsIdAndTypeId(storeUid, staffUid, goodsId, goodsTypeId, 0, 0);
            if (data == null) {
                if (num > stockNum)
                    return R.fail("购买数量不能超过库存数量库存：" + stockNum);
                // 新增普通商品购物车记录
                data = ShopCartUtilV2.newShopCart(
                        goods, goodsType, storesCorpUid, storeUid, staffUid,
                        EnumType.ShopCartType.ADD.getType(), goodsType.getComboType(), KitUtil.getUuid(), num,
                        staffUid, staffName, null, storeGoodsDiscountRate
                );
            } else {
                // 更新普通商品购物车购买数量
                int buyNum = data.getBuyNum() + num;
                if (buyNum > stockNum)
                    return R.fail("购物车内商品数量已超过库存数量");
                // 修改组合商品规格的购物车记录
                ShopCartUtilV2.mdyShopCart(
                        data, goods, goodsType, buyNum, staffUid, staffName, storeGoodsDiscountRate
                );
            }
            saveOrUpdate(data);
        } else {
            // 组合商品
            // 获取组合商品的商品配置集合
            List<GoodsTypeCombo> goodsTypeComboList = goodsTypeComboService.listByMainGoodsIdAndMainGoodsTypeId(goodsId, goodsTypeId);
            if (CollectionUtils.isEmpty(goodsTypeComboList))
                return R.fail("组合商品内的商品规格获取失败");

            HashBasedTable<Long, Long, GoodsTypeCombo> table = HashBasedTable.create();
            for (GoodsTypeCombo goodsTypeCombo : goodsTypeComboList) {
                table.put(goodsTypeCombo.getGoodsTypeId(), goodsTypeCombo.getGoodsId(), goodsTypeCombo);
            }
            List<Long> childGoodsIds = new ArrayList<>(table.columnKeySet());
            List<Long> childGoodsTypeIds = new ArrayList<>(table.rowKeySet());

            List<Goods> childGoodsList = goodsService.listByIds(childGoodsIds);
            if (CollectionUtils.isEmpty(childGoodsList) || childGoodsIds.size() != childGoodsList.size())
                return R.fail("组合商品内的商品获取失败");
            List<GoodsType> childGoodsTypeList = goodsTypeService.listByIds(childGoodsTypeIds);
            if (CollectionUtils.isEmpty(childGoodsTypeList) || childGoodsTypeIds.size() != childGoodsTypeList.size())
                return R.fail("组合商品内的商品规格获取失败");

            Map<Long, Goods> childGoodsMap = childGoodsList.stream().collect(Collectors.toMap(Goods::getId, Function.identity()));
            Map<Long, GoodsType> childGoodsTypeMap = childGoodsTypeList.stream().collect(Collectors.toMap(GoodsType::getId, Function.identity()));

            for (Goods childGoods : childGoodsList) {
                if (childGoods.getEnabled().equals(0)) {
                    return R.fail("组合商品内的商品已下架" + childGoods.getName());
                }
            }
            for (GoodsType childGoodsType : childGoodsTypeList) {
                if (childGoodsType.getEnabled().equals(0)) {
                    Goods childGoods = childGoodsMap.get(childGoodsType.getGoodsId());
                    return R.fail("组合商品内的商品规格已下架" + childGoods.getName() + "/" + childGoodsType.getName());
                }
            }

            // 获取库存数量
            Map<Long, Integer> stockNumMap = stockInService.getStockNumMap(childGoodsTypeIds);
            // 根据购买记录和出库记录获取商品规格的待出库数量
            Map<Long, Integer> waitSendNumMap = getWaitSendNum(childGoodsTypeIds);

            double totalWeight = 0;
            // 商品、组合商品规格、组合子商品，只要有一个是银行转账，主购物车记录就是银行转账
            int paymentMethod = goods.getPaymentMethod();

            data = getByStaffIdAndGoodsIdAndTypeId(storeUid, staffUid, goodsId, goodsTypeId, 1, 1);
            if (data == null) {
                // 新增组合商品购物车记录
                String mainUid = KitUtil.getUuid();
                List<ShopCart> newList = new ArrayList<>();
                for (Table.Cell<Long, Long, GoodsTypeCombo> cell : table.cellSet()) {
                    Long cellGoodsId = cell.getColumnKey();
                    Long cellTypeIdKey = cell.getRowKey();
                    GoodsTypeCombo goodsTypeCombo = cell.getValue();
                    if (goodsTypeCombo == null)
                        return R.fail("组合商品的商品配置获取失败");

                    Goods childGoods = childGoodsMap.get(cellGoodsId);
                    GoodsType childGoodsType = childGoodsTypeMap.get(cellTypeIdKey);
                    if (childGoods == null || childGoodsType == null)
                        return R.fail("组合商品内的商品未查询到");

                    Integer waitSendNum = waitSendNumMap.get(goodsTypeCombo.getGoodsTypeId());
                    Integer stockNum = stockNumMap.get(goodsTypeCombo.getGoodsTypeId());
                    // 获取商品规格的真实可售数，库存数量减去待发货数量
                    stockNum = OrderFormV3Util.getGoodsTypeNum(stockNum, waitSendNum);

                    // 组合商品规定的子商品规格的购买数量
                    Integer goodsTypeComboNum = goodsTypeCombo.getNum();
                    // 商品规格真实购买数=购买数*组合内规定的购买数量
                    int buyNum = num * goodsTypeComboNum;
                    if (buyNum > stockNum)
                        return R.fail("组合商品内的商品库存数量不足，" + childGoods.getName() + "/" + childGoodsType.getName() + " 库存：" + stockNum);

                    // 包含有银行转账
                    if (paymentMethod == 1 && childGoods.getPaymentMethod().equals(2))
                        paymentMethod = 2;

                    ShopCart childCart = ShopCartUtilV2.newChildComboShopCart(
                            childGoods, childGoodsType, storesCorpUid, storeUid, staffUid,
                            EnumType.ShopCartType.ADD.getType(), goodsType.getComboType(), KitUtil.getUuid(), buyNum, staffUid, staffName,
                            mainUid, goods.getId(), goods.getName(), goodsType.getId(), goodsType.getName(), null
                    );

                    totalWeight = DoubleUtil.sum(totalWeight, childCart.getTotalWeight());

                    newList.add(childCart);
                }

                // 添加组合商品的购物车记录
                data = ShopCartUtilV2.newMainComboShopCart(
                        goods, goodsType, storesCorpUid, storeUid, staffUid,
                        EnumType.ShopCartType.ADD.getType(), goodsType.getComboType(), mainUid, num, staffUid, staffName,
                        paymentMethod, totalWeight, null, storeGoodsDiscountRate
                );
                newList.add(0, data);
                // 新增组合商品购物车记录
                saveOrUpdateBatch(newList);
            } else {
                // 更新组合商品购物车记录
                List<ShopCart> childShopCartList = childListByStoreUidAndStaffUidAndUid(storeUid, staffUid, data.getUid());
                if (CollectionUtils.isEmpty(childShopCartList))
                    return R.fail("组合商品内的购物车记录获取失败");

                int buyNum = data.getBuyNum() + num;
                List<ShopCart> newList = new ArrayList<>();

                for (ShopCart childCart : childShopCartList) {
                    Goods childGoods = childGoodsMap.get(childCart.getGoodsId());
                    GoodsType childGoodsType = childGoodsTypeMap.get(childCart.getGoodsTypeId());
                    if (childGoods == null || childGoodsType == null)
                        return R.fail("组合商品内的商品未查询到");
                    GoodsTypeCombo goodsTypeCombo = table.get(childCart.getGoodsTypeId(), childCart.getGoodsId());
                    if (goodsTypeCombo == null)
                        return R.fail("组合商品的商品配置获取失败");

                    Integer waitSendNum = waitSendNumMap.get(childCart.getGoodsTypeId());
                    Integer stockNum = stockNumMap.get(childCart.getGoodsTypeId());
                    // 获取商品规格的真实可售数，库存数量减去待发货数量
                    stockNum = OrderFormV3Util.getGoodsTypeNum(stockNum, waitSendNum);

                    // 组合商品规定的子商品规格的购买数量
                    Integer goodsTypeComboNum = goodsTypeCombo.getNum();
                    // 商品规格真实购买数=购买数*组合内规定的购买数量
                    int childBuyNum = buyNum * goodsTypeComboNum;
                    if (childBuyNum > stockNum)
                        return R.fail("组合商品内的商品库存数量不足，" + childGoods.getName() + "/" + childGoodsType.getName() + " 库存：" + stockNum);

                    // 包含有银行转账
                    if (paymentMethod == 1 && childGoods.getPaymentMethod().equals(2))
                        paymentMethod = 2;

                    // 修改组合商品规格的购物车记录
                    ShopCartUtilV2.mdyShopCart(
                            childCart, childGoods, childGoodsType, childBuyNum, staffUid, staffName, null
                    );

                    totalWeight = DoubleUtil.sum(totalWeight, childCart.getTotalWeight());

                    newList.add(childCart);
                }
                // 修改组合商品规格的购物车记录
                ShopCartUtilV2.mdyMainComboShopCart(
                        data, goods, goodsType, buyNum, paymentMethod, totalWeight, staffUid, staffName, storeGoodsDiscountRate
                );
                newList.add(data);
                // 更新组合商品购物车记录
                saveOrUpdateBatch(newList);
            }
        }

        return R.ok(data.getId());
    }

    @Override
    public R<Object> getShopCartInfo(String storeUid, String staffUid, Long couponStaffId, List<Long> shopCartIds) {
        if (CollectionUtils.isEmpty(shopCartIds))
            return R.fail("请选择商品");

        Stores stores = storesService.getByUid(storeUid);
        if (null == stores)
            return R.fail("门店信息获取失败");
        if (StringUtils.isBlank(stores.getProvince()))
            return R.fail("门店未设置省市区信息");

        List<ShopCart> shopCartList = listRelationByIdInOrderByPrice(shopCartIds);
        if (CollectionUtils.isEmpty(shopCartList))
            return R.fail("未查询到购物车商品信息");

        boolean selfStore = AccountUtil.isSelfStore(stores.getOperationType());
        // 验证购物车商品是否有效
        R<ShopCartCheckDto> r = OrderFormV3Util.verifyShopCartToOrder(
                shopCartList, storeUid, staffUid, selfStore, false, couponStaffId
        );
        if (R.isError(r))
            return R.fail(r.getMsg());

        ShopCartCheckDto checkDto = r.getData();
        if (checkDto == null)
            return R.fail("购物车商品校验失败");

        ShopCartResultDto resultDto = new ShopCartResultDto();
        resultDto.setNum(checkDto.getNum());
        resultDto.setTotalWeight(checkDto.getTotalWeight());
        resultDto.setPrice(checkDto.getPrice());
        resultDto.setPayPrice(checkDto.getPayPrice());
        resultDto.setPaymentMethod(checkDto.getPaymentMethod());

        resultDto.setCouponName(checkDto.getCouponName());
        resultDto.setCouponStaffId(checkDto.getCouponStaffId());
        resultDto.setDeductionPrice(checkDto.getDeductionPrice());
        resultDto.setDiscountPrice(checkDto.getDiscountPrice());
        resultDto.setOriginalPrice(checkDto.getOriginalPrice());

        // 区分能否包邮
        List<ShopCart> cartList = checkDto.getShopCartList();
        List<ShopCart> childShopCartList = checkDto.getChildShopCartList();
        OrderFormV3Util.setFreeDelivery(cartList, childShopCartList, checkDto.getGoodsTypeMap(), selfStore ? 1 : 2, false, stores.getProvince());
        Map<Integer, List<ShopCart>> deliveryCartMap = cartList.stream().collect(Collectors.groupingBy(ShopCart::getFreeDeliveryStatus));
        resultDto.setFreeDeliveryList(deliveryCartMap.get(1));
        resultDto.setNotFreeDeliveryList(deliveryCartMap.get(0));

        return R.ok(resultDto);
    }

    @Override
    public R<Object> nowNewShopCart(String storeUid, String staffUid, String staffName, Long goodsId, Long goodsTypeId, Integer num, String remark) {
        if (num <= 0)
            return R.fail("购买数量必须大于0");

        Stores stores = storesService.getByUid(storeUid);
        if (null == stores)
            return R.fail("门店信息获取失败");
        String storesCorpUid = stores.getCorpUid();

        Goods goods = goodsService.getById(goodsId);
        if (goods == null)
            return R.fail("商品获取失败");
        if (!goods.getEnabled().equals(1))
            return R.fail("商品已下架");
        if (goods.getFreeDeliveryId() == null || goods.getFreeDeliveryId() <= 0)
            return R.fail("商品未设置包邮模板");

        GoodsType goodsType = goodsTypeService.getByGoodsIdAndGoodsTypeId(goodsId, goodsTypeId);
        if (goodsType == null)
            return R.fail("商品规格获取失败");
        if (!goodsType.getEnabled().equals(1))
            return R.fail("商品规格已下架");

        // 轻量门店的商品折扣规则
        Double storeGoodsDiscountRate = storeGoodsDiscountService.getDiscountRate(storeUid);

        ShopCart data = null;
        if (goodsType.getComboType().equals(0)) {
            // 普通商品
            // 获取库存数量
            Map<Long, Integer> stockNumMap = stockInService.getStockNumMap(Collections.singletonList(goodsTypeId));
            int stockNum = stockNumMap.get(goodsTypeId);
            // 根据购买记录和出库记录获取商品规格的待出库数量
            int waitSendNum = getWaitSendNum(goodsTypeId);

            // 判断商品和商品规格状态
            String msg = OrderFormV3Util.judgeGoodsAndGoodsType(
                    AccountUtil.isSelfStore(stores.getOperationType()), goodsType.getComboType(), goods, goodsType,
                    num, stockNum, waitSendNum
            );
            if (StringUtils.isNotBlank(msg))
                return R.fail(msg);

            data = ShopCartUtilV2.newShopCart(
                    goods, goodsType, storesCorpUid, storeUid, staffUid, EnumType.ShopCartType.NOW_BUY.getType(), goodsType.getComboType(),
                    KitUtil.getUuid(), num, staffUid, staffName, null, storeGoodsDiscountRate
            );
            saveOrUpdate(data);
        } else {
            // 组合商品
            // 获取组合商品的商品配置集合
            List<GoodsTypeCombo> goodsTypeComboList = goodsTypeComboService.listByMainGoodsIdAndMainGoodsTypeId(goodsId, goodsTypeId);
            if (CollectionUtils.isEmpty(goodsTypeComboList))
                return R.fail("组合商品内的商品规格获取失败");

            HashBasedTable<Long, Long, GoodsTypeCombo> table = HashBasedTable.create();
            for (GoodsTypeCombo goodsTypeCombo : goodsTypeComboList) {
                table.put(goodsTypeCombo.getGoodsTypeId(), goodsTypeCombo.getGoodsId(), goodsTypeCombo);
            }
            List<Long> childGoodsIds = new ArrayList<>(table.columnKeySet());
            List<Long> childGoodsTypeIds = new ArrayList<>(table.rowKeySet());

            List<Goods> childGoodsList = goodsService.listByIds(childGoodsIds);
            if (CollectionUtils.isEmpty(childGoodsList) || childGoodsIds.size() != childGoodsList.size())
                return R.fail("组合商品内的商品获取失败");
            List<GoodsType> childGoodsTypeList = goodsTypeService.listByIds(childGoodsTypeIds);
            if (CollectionUtils.isEmpty(childGoodsTypeList) || childGoodsTypeIds.size() != childGoodsTypeList.size())
                return R.fail("组合商品内的商品规格获取失败");

            Map<Long, Goods> childGoodsMap = childGoodsList.stream().collect(Collectors.toMap(Goods::getId, Function.identity()));
            Map<Long, GoodsType> childGoodsTypeMap = childGoodsTypeList.stream().collect(Collectors.toMap(GoodsType::getId, Function.identity()));

            for (GoodsType childGoodsType : childGoodsTypeList) {
                if (childGoodsType.getEnabled().equals(0)) {
                    Goods childGoods = childGoodsMap.get(childGoodsType.getGoodsId());
                    return R.fail("组合商品内的商品规格已下架" + childGoods.getName() + "/" + childGoodsType.getName());
                }
            }

            // 获取库存数量
            Map<Long, Integer> stockNumMap = stockInService.getStockNumMap(childGoodsTypeIds);
            // 根据购买记录和出库记录获取商品规格的待出库数量
            Map<Long, Integer> waitSendNumMap = getWaitSendNum(childGoodsTypeIds);

            // 新增组合商品购物车记录
            List<ShopCart> newList = new ArrayList<>();
            double totalWeight = 0;
            // 商品、组合商品规格、组合子商品，只要有一个是银行转账，主购物车记录就是银行转账
            int paymentMethod = goods.getPaymentMethod();
            String mainUid = KitUtil.getUuid();
            for (Table.Cell<Long, Long, GoodsTypeCombo> cell : table.cellSet()) {
                Long cellGoodsId = cell.getColumnKey();
                Long cellTypeIdKey = cell.getRowKey();
                GoodsTypeCombo goodsTypeCombo = cell.getValue();
                if (goodsTypeCombo == null)
                    return R.fail("组合商品的商品配置获取失败");

                Goods childGoods = childGoodsMap.get(cellGoodsId);
                GoodsType childGoodsType = childGoodsTypeMap.get(cellTypeIdKey);
                if (childGoods == null || childGoodsType == null)
                    return R.fail("组合商品内的商品未查询到");

                Integer waitSendNum = waitSendNumMap.get(goodsTypeCombo.getGoodsTypeId());
                Integer stockNum = stockNumMap.get(goodsTypeCombo.getGoodsTypeId());
                // 获取商品规格的真实可售数，库存数量减去待发货数量
                stockNum = OrderFormV3Util.getGoodsTypeNum(stockNum, waitSendNum);

                // 组合商品规定的子商品规格的购买数量
                Integer goodsTypeComboNum = goodsTypeCombo.getNum();
                // 商品规格真实购买数=购买数*组合内规定的购买数量
                int buyNum = num * goodsTypeComboNum;
                if (buyNum > stockNum)
                    return R.fail("组合商品内的商品库存数量不足，" + childGoods.getName() + "/" + childGoodsType.getName() + " 库存：" + stockNum);

                // 包含有银行转账
                if (paymentMethod == 1 && childGoods.getPaymentMethod().equals(2))
                    paymentMethod = 2;

                ShopCart childCart = ShopCartUtilV2.newChildComboShopCart(
                        childGoods, childGoodsType, storesCorpUid, storeUid, staffUid,
                        EnumType.ShopCartType.NOW_BUY.getType(), goodsType.getComboType(), KitUtil.getUuid(), buyNum, staffUid, staffName,
                        mainUid, goods.getId(), goods.getName(), goodsType.getId(), goodsType.getName(), null
                );

                totalWeight = DoubleUtil.sum(totalWeight, childCart.getTotalWeight());
                newList.add(childCart);
            }

            // 添加组合商品规格的购物车记录
            data = ShopCartUtilV2.newMainComboShopCart(
                    goods, goodsType, storesCorpUid, storeUid, staffUid,
                    EnumType.ShopCartType.NOW_BUY.getType(), goodsType.getComboType(), mainUid, num, staffUid, staffName,
                    paymentMethod, totalWeight, null, storeGoodsDiscountRate
            );
            newList.add(data);

            // 新增组合商品购物车记录
            saveOrUpdateBatch(newList);
        }

        return R.ok(data.getId());
    }

    @Override
    public R<Object> getCouponAndDeliveryAddress(String storeUid, String staffUid, List<Long> shopCartIds) {
        // 获取收货地址
        DeliveryAddress address = deliveryAddressService.getDefault(storeUid, staffUid);
        DeliveryAddressDto addressDto = null;
        if (address != null)
            addressDto = OrderFormV3Util.getAddressDto(address);

        List<ShopCart> shopCartList = listRelationByIdIn(shopCartIds);
        if (CollectionUtils.isEmpty(shopCartList))
            return R.fail("未查询到购物车商品信息");

        // 套装内的商品不参与商品抵扣券
        List<Long> goodsIdList = shopCartList.stream()
                .filter(cart -> cart.getMainComboType().equals(0) || (cart.getMainComboType().equals(1) && cart.getComboType().equals(1)))
                .map(ShopCart::getGoodsId)
                .collect(Collectors.toList());

        List<Goods> goodsList = goodsService.listByIds(goodsIdList);
        if (CollectionUtils.isEmpty(goodsList))
            return R.fail("未查询到商品信息");
        Map<Long, Goods> goodsMap = goodsList.stream().collect(Collectors.toMap(Goods::getId, Function.identity()));

        double useCouponPrice = 0d;
        for (ShopCart cart : shopCartList) {
            Goods goods = goodsMap.get(cart.getGoodsId());
            if (goods == null) {
                return R.fail(cart.getGoodsName() + "-" + cart.getGoodsTypeName() + "，未查询到该商品信息");
            }
            if (goods.getCouponStatus() != null && goods.getCouponStatus().equals(1)) {
                useCouponPrice = DoubleUtil.sum(useCouponPrice, cart.getPrice());
            }
        }

        // 查询商品的分类是否满足商品分类代金券
        List<Long> categoryIdList =new ArrayList<>();
        List<GoodsCategoryLog> goodsCategoryLogs = goodsCategoryLogService.listByGoodsIdIn(goodsIdList);
        if (CollectionUtils.isNotEmpty(goodsCategoryLogs)) {
            categoryIdList = goodsCategoryLogs.stream().map(GoodsCategoryLog::getCategoryId).distinct().collect(Collectors.toList());
        }

        // 员工可使用的代金券集合
        List<CouponStaffDto> couponStaffList = null;
        // 员工不可使用的代金券集合
        List<CouponStaffDto> couponStaffNoList = null;
        if (useCouponPrice > 0) {
            couponStaffList = couponStaffService.getOrderUseCouponV2(storeUid, staffUid, useCouponPrice, goodsIdList, categoryIdList);
            if (CollectionUtils.isNotEmpty(couponStaffList)) {
                // 有效但不可使用的代金券
                List<Long> couponStaffIdList = couponStaffList.stream().map(CouponStaffDto::getId).collect(Collectors.toList());
                couponStaffNoList = couponStaffService.getOrderNotUseCouponV2(storeUid, staffUid, couponStaffIdList);
            }
        }

        CouponAndAddressDto dto = new CouponAndAddressDto();
        dto.setAddress(addressDto);
        dto.setCouponStaffList(couponStaffList);
        dto.setCouponStaffNoList(couponStaffNoList);
        return R.ok(dto);
    }

    @Override
    public R<Object> newOrder(String corpUid, String storeUid, String storeName, String staffUid, String staffName, List<Long> shopCartIds, Long deliveryId, Long couponStaffId, String remark) {
        if (CollectionUtils.isEmpty(shopCartIds))
            return R.fail("请选择商品");

        Stores stores = storesService.getByUid(storeUid);
        if (null == stores)
            return R.fail("门店信息获取失败");
        if (StringUtils.isBlank(stores.getProvince()))
            return R.fail("门店未设置省市区信息");

        Corporations corporations = corporationsService.getByUid(stores.getCorpUid());
        if (corporations == null)
            return R.fail("公司获取失败");

        DeliveryAddress delivery = deliveryAddressService.getById(deliveryId);
        if (delivery == null) return R.fail("收货地址获取失败");

        List<ShopCart> shopCartList = listRelationByIdIn(shopCartIds);
        if (CollectionUtils.isEmpty(shopCartList))
            return R.fail("商品获取失败");

        List<String> shopCartUids = shopCartList.stream().map(ShopCart::getUid).collect(Collectors.toList());

        // 判断自营门店
        boolean selfStore = AccountUtil.isSelfStore(stores.getOperationType());

        // 创建订单时判断购物车是否有效
        R<ShopCartCheckDto> r = OrderFormV3Util.verifyShopCartToOrder(
                shopCartList, storeUid, staffUid, selfStore, true, couponStaffId
        );
        if (R.isError(r))
            return R.fail(r.getMsg());

        ShopCartCheckDto checkDto = r.getData();
        // 订单购买的总数量
        int totalBuyNum = checkDto.getNum();
        // 订单商品总重量
        double totalWeight = checkDto.getTotalWeight();
        // 订单总金额
        double totalPrice = checkDto.getPrice();
        // 订单支付金额
        double payPrice = checkDto.getPayPrice();
        // 订单原价总金额
        double originalPrice = checkDto.getOriginalPrice();
        // 代金券抵扣金额
        double deductionPrice = checkDto.getDeductionPrice();
        // 商品折扣金额
        double discountPrice = checkDto.getDiscountPrice();
        // 代金券名称
        String couponName = checkDto.getCouponName();
        // 付款方式
        int paymentMethod = checkDto.getPaymentMethod();
        // 收款公司
        int payCorp = checkDto.getPayCorp();
        checkDto.getCouponName();
        // 商品规格
        Map<Long, GoodsType> goodsTypeMap = checkDto.getGoodsTypeMap();

        // 区分能否包邮
        List<ShopCart> cartList = checkDto.getShopCartList();
        List<ShopCart> childShopCartList = checkDto.getChildShopCartList();
        OrderFormV3Util.setFreeDelivery(cartList, childShopCartList, goodsTypeMap, selfStore ? 1 : 2, true, stores.getProvince());

        // 创建商品订单
        OrderForm form = new OrderForm();
        // 商品规格数量
        form.setGoodsTypeNum(shopCartUids.size());
        // 商品购买数量
        form.setBuyNum(totalBuyNum);
        // 订单商品总重量
        form.setWeight(totalWeight);
        // 订单总金额
        form.setPrice(originalPrice);
        // 订单支付金额
        form.setPayPrice(payPrice);
        // 订单的付款方式
        form.setPaymentMethod(paymentMethod);
        // 收款公司
        form.setPayCorp(payCorp);
        // 代金券信息
        form.setCouponName(couponName);
        form.setCouponStaffId(couponStaffId);
        form.setCouponPrice(deductionPrice);
        form.setDiscountPrice(discountPrice);

        // 自营门店，实际支付金额设为0
        if (selfStore) {
            form.setPayPrice(0d);
            form.setPayChannelCode(EnumType.PayChannelCode.SELF.getType());
        }
        // 签单人默认是门店的运营人员
        if (StringUtils.isNotBlank(stores.getOperateStaffUid())) {
            form.setSaleStaffUid(stores.getOperateStaffUid());
            form.setSaleStaffName(stores.getOperateStaffName());
            form.setSaleStaffPhone(stores.getOperateStaffPhone());
        }

        String code = KitUtil.getGoodsCode();
        form.setCorpUid(stores.getCorpUid());
        form.setCorpName(corporations.getCorpName());
        form.setStoreUid(storeUid);
        form.setStoreName(storeName);
        form.setStaffUid(staffUid);
        form.setStaffName(staffName);
        form.setCode(code);
        form.setProjectType(EnumType.BalanceProject.BUY_GOODS.getType());
        form.setProjectName(EnumType.BalanceProject.BUY_GOODS.getName());
        form.setStatus(EnumType.OrderForm.WAIT_CONFIRM.getType());
        form.setStatusName(EnumType.OrderForm.WAIT_CONFIRM.getName());
        form.setRemark(remark);
        form.setAddStaffUid(staffUid);
        form.setAddStaffName(staffName);
        form.setLastStaffUid(staffUid);
        form.setLastStaffName(staffName);
        // 收货地址
        form.setDeliveryId(deliveryId);
        form.setName(delivery.getName());
        form.setPhone(delivery.getPhone());
        form.setAddress(delivery.getProvinces() + delivery.getAddress());
        orderFormService.saveOrUpdate(form);

        // 更新购物车的订单编号和相关金额
        updateFormInfo(shopCartUids, form.getCode());
        dbUpdatePriceInfo(checkDto.getUpdatePriceList());

        // 非自营门店，未付款的商城订单过期后自动取消
        if (!selfStore) {
            OrderFormV3Util.addMallCodeToRedisExpire(code);
        }

        // 发送企业微信消息通知
        String accessToken = (String) redisService.get(RedisParam.QYWEINXIN_ACCESS_TOKEN);
        if (StringUtils.isBlank(accessToken)) {
            AccessTokenDto dto = QyWeiXinUtil.getAccessToken(corpid, secret);
            if (dto != null) {
                accessToken = dto.getAccess_token();
                int expires_in = dto.getExpires_in();
                // redis缓存accessToken
                redisService.set(RedisParam.QYWEINXIN_ACCESS_TOKEN, accessToken, expires_in);
            }
        }
        if (AccountUtil.isJointOperation(stores.getOperationType(), staffUid)) {
            // 采购或联营店订单
            QyWeiXinUtil.sendToUser(accessToken, agentid, thirdUserid, QyWeixinMsg.jointOperationConfirmFreeOrderMsg(serverUrl, "采购或联营店订单", form.getStoreName(), form.getCode()));
        } else {
            if (selfStore) {
                // 自营门店订单
                QyWeiXinUtil.sendToUser(accessToken, agentid, managerUserid, QyWeixinMsg.confirmFreeOrderMsg(serverUrl, "自营门店订单", form.getStoreName(), form.getCode()));
                QyWeiXinUtil.sendToUser(accessToken, agentid, subManagerUserid, QyWeixinMsg.confirmFreeOrderMsg(serverUrl, "自营门店订单", form.getStoreName(), form.getCode()));
            } else {
                // 加盟店订单
                QyWeiXinUtil.sendToChat(accessToken, mallchatid, QyWeixinMsg.confirmOrderMsg(serverUrl, form.getStoreName(), form.getCode()));
            }
        }

        return R.ok(form.getCode());
    }

    @Override
    public List<ShopCart> childListByStoreUidAndStaffUidAndUid(String storeUid, String staffUid, String mainShopCartUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.type.eq(1))
                .and(table.code.isNull())
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.comboType.eq(0))
                .and(table.mainComboType.eq(1))
                .and(table.mainShopCartUid.eq(mainShopCartUid));

        return getMapper().selectListByCondition(condition);
    }

    @Override
    public long getStaffShopCartCountV3(String storeUid, String staffUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.type.eq(1))
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                // 排除组合子商品
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));
        return getMapper().selectCountByCondition(condition);
    }


    @Override
    public int getWaitSendNum(Long goodsTypeId) {
        Integer waitSendNum = shopCartMapper.getWaitSendNum(goodsTypeId);
        return NepUtil.nullToZero(waitSendNum);
    }

    @Override
    public Map<Long, Integer> getWaitSendNum(List<Long> goodsTypeIds) {
        // 结果,默认值设置0
        Map<Long, Integer> map = new HashMap<>();
        for (Long goodsTypeId : goodsTypeIds) {
            map.put(goodsTypeId, 0);
        }
        List<JSONObject> list = shopCartMapper.getWaitSendNumList(goodsTypeIds);
        if (CollectionUtils.isNotEmpty(list)) {
            for (JSONObject jsonObject : list) {
                Long goodsTypeId = jsonObject.getLong("goodsTypeId");
                Integer cnt = jsonObject.getInteger("cnt");
                if (goodsTypeId != null && cnt != null) {
                    map.put(goodsTypeId, NepUtil.nullToZero(cnt));
                }
            }
        }
        return map;
    }

    @Override
    public ShopCart getByStaffIdAndGoodsIdAndTypeId(String storeUid, String staffUid, Long goodsId, Long goodsTypeId, Integer mainComboType, Integer comboType) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.goodsId.eq(goodsId))
                .and(table.goodsTypeId.eq(goodsTypeId))
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.type.eq(1))
                .and(table.mainComboType.eq(mainComboType))
                .and(table.comboType.eq(comboType));
        return getMapper().selectOneByCondition(condition);
    }


    @Override
    public void dbUpdateDeliveryStatus(List<UpdateShopCartVo> voList) {
        String sql = "update shop_cart set free_delivery_id=?, free_delivery_name=?, free_delivery_status=? where uid=?";
        Db.updateBatch(sql, new BatchArgsSetter() {
            @Override
            public int getBatchSize() {
                return voList.size();
            }

            @Override
            public Object[] getSqlArgs(int index) {
                UpdateShopCartVo vo = voList.get(index);
                Object[] args = new Object[4];
                args[0] = vo.getDeliveryId();
                args[1] = vo.getDeliveryName();
                args[2] = vo.getDeliveryStatus();
                args[3] = vo.getUid();
                return args;
            }
        });
    }

    /**
     * 取消购物车记录
     */
    public void cancelShopCarts(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(staffUid))
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code))
                .and(table.status.in(EnumType.ShopCart.WAIT_CONFIRM.getType(), EnumType.ShopCart.WAIT_PAY.getType()));

        UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.CANCEL.getType())
                .set(table.statusName, EnumType.ShopCart.CANCEL.getName())
                .where(condition)
                .update();
    }

    @Override
    public List<ShopCart> mainListAndChildListByCode(String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.asc());
        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public List<ShopCart> mainListByCodeIn(List<String> codes) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.in(codes))
                // 排除组合子商品
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));

        return getMapper().selectListByCondition(condition);
    }

    @Override
    public List<ShopCart> mainListByStaffUidAndCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.staffUid.eq(staffUid))
                .and(table.code.eq(code))
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.freeDeliveryStatus.asc(), table.mainComboType.asc(), table.stockOutMethod.asc());

        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public List<ShopCart> childListByStoreUidAndStaffUidAndUidsAndCodeIsNull(String storeUid, String staffUid, List<String> mainShopCartUids) {
        QueryCondition condition = table.code.isNull()
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.comboType.eq(0))
                .and(table.mainComboType.eq(1))
                .and(table.mainShopCartUid.in(mainShopCartUids));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition);
        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public List<ShopCart> getByCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public void setOk(String code, String payTimes) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.status.in(EnumType.ShopCart.WAIT_CONFIRM.getType(), EnumType.ShopCart.WAIT_PAY.getType()));

        UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.PAYED.getType())
                .set(table.statusName, EnumType.ShopCart.PAYED.getName())
                .set(table.payTimes, payTimes)
                .where(condition)
                .update();
    }

    private List<ShopCart> listRelationByIdIn(List<Long> shopCartIds) {
        QueryWrapper wrapper = QueryWrapper.create()
                .where(table.id.in(shopCartIds))
                .orderBy(table.id.desc());
        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    private List<ShopCart> listRelationByIdInOrderByPrice(List<Long> shopCartIds) {
        QueryWrapper wrapper = QueryWrapper.create()
                .where(table.id.in(shopCartIds))
                .orderBy(table.originalPrice.desc());
        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    /**
     * 购物车和组合子购物车更新订单编号
     */
    private void updateFormInfo(List<String> shopCartUids, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.uid.in(shopCartUids).or(table.mainShopCartUid.in(shopCartUids)));

        UpdateChain.of(ShopCart.class)
                .set(table.code, code)
                .where(condition)
                .update();
    }

    /**
     * 批量更新购物车商品的金额信息
     */
    private void dbUpdatePriceInfo(List<UpdateShopCartVo> voList) {
        String sql = "update shop_cart set price=?, deduction_price=?, discount_price=? where uid=?";
        Db.updateBatch(sql, new BatchArgsSetter() {
            @Override
            public int getBatchSize() {
                return voList.size();
            }

            @Override
            public Object[] getSqlArgs(int index) {
                UpdateShopCartVo vo = voList.get(index);
                Object[] args = new Object[4];
                args[0] = vo.getPrice();
                args[1] = vo.getDeductionPrice();
                args[2] = vo.getDiscountPrice();
                args[3] = vo.getUid();
                return args;
            }
        });
    }

}
